package com.easonji.core.aop;

import java.lang.reflect.UndeclaredThrowableException;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.UnknownSessionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.easonji.common.base.response.Response;
import com.easonji.common.base.response.enums.ResponseEnum;
import com.easonji.common.constant.enums.message.MessageEnum;
import com.easonji.common.util.HttpUtils;
import com.easonji.config.properties.SysProperties;
import com.easonji.core.exception.BizException;
import com.easonji.core.log.LogManager;
import com.easonji.core.log.factory.LogTaskFactory;
import com.easonji.core.shiro.util.ShiroUtils;

/**
 * @ClassName: GlobalExceptionHandler
 * @Description: 全局的的异常拦截器（拦截所有的控制器）
 * @Author: LiuJun
 * @date: 2018/07/18 18:01
 * @Version: 1.0
 * @Copyright: Copyright (c) 2018 - 2019
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    private SysProperties sysProperties;

    /**
     * 拦截业务异常
     */
    @ResponseBody
    @ExceptionHandler(BizException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Response notFount(BizException e) {
        Response response = new Response();
        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroUtils.getUser().getUserId(), e));
        log.error("业务异常:", e);
        response.setSuccess(false);
        response.setCode(e.getCode());
        response.setMessage(e.getMessage());
        return response;
    }

    /**
     * 拦截未知的运行时异常
     */
    @ResponseBody
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Response notFount(RuntimeException e) {
        Response response = new Response();
        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroUtils.getUser().getUserId(), e));
        log.error("运行时异常:", e);
        response.setSuccess(false);
        response.setCode(ResponseEnum.SYSTEM_ERROR.getCode());
        response.setMessage(ResponseEnum.SYSTEM_ERROR.getMessage());
        return response;
    }

    /**
     * 无权访问该资源
     */
    @ResponseBody
    @ExceptionHandler(UndeclaredThrowableException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Response credentials(UndeclaredThrowableException e) {
        Response response = new Response();
        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroUtils.getUser().getUserId(), e));
        log.error("权限异常!", e);
        response.setSuccess(false);
        response.setCode(MessageEnum.NO_PERMITION.getCode());
        response.setMessage(MessageEnum.NO_PERMITION.getMessage());
        return response;
    }

    /**
     * 用户未登录
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String unAuth(Model model) {
        model.addAttribute("tip", "用户未登陆");
        model.addAttribute("kaptchaOpen", sysProperties.getKaptchaOpen());
        return "/login";
    }

    /**
     * 账号被冻结
     */
    @ExceptionHandler(LockedAccountException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String accountLocked(Model model) {
        String userName = HttpUtils.getRequest().getParameter("userName");
        LogManager.me().executeLog(LogTaskFactory.loginLog(userName, "账号被冻结", HttpUtils.getIp()));
        model.addAttribute("tip", "账号被冻结");
        model.addAttribute("kaptchaOpen", sysProperties.getKaptchaOpen());
        return "/login";
    }

    /**
     * 账号密码错误
     */
    @ExceptionHandler(CredentialsException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String credentials(Model model) {
        String userName = HttpUtils.getRequest().getParameter("userName");
        LogManager.me().executeLog(LogTaskFactory.loginLog(userName, "账号密码错误", HttpUtils.getIp()));
        model.addAttribute("kaptchaOpen", sysProperties.getKaptchaOpen());
        model.addAttribute("tip", "账号密码错误");
        return "/login";
    }

    /**
     * session失效的异常拦截
     */
    @ExceptionHandler(InvalidSessionException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String sessionTimeout(Model model, HttpServletRequest request, HttpServletResponse response) {
        model.addAttribute("tip", "session超时");
        model.addAttribute("kaptchaOpen", sysProperties.getKaptchaOpen());
        assertAjax(request, response);
        return "/login";
    }

    /**
     * session异常
     */
    @ExceptionHandler(UnknownSessionException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String sessionException(Model model, HttpServletRequest request, HttpServletResponse response) {
        model.addAttribute("tip", "session异常");
        model.addAttribute("kaptchaOpen", sysProperties.getKaptchaOpen());
        assertAjax(request, response);
        return "/login";
    }

    private void assertAjax(HttpServletRequest request, HttpServletResponse response) {
        final String headler = "x-requested-with";
        if (request.getHeader(headler) != null
                && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
            // 如果是ajax请求响应头会有，x-requested-with
            // 在响应头设置session状态
            response.setHeader("sessionstatus", "timeout");
        }
    }
}
